<template>
    <div>
        <el-upload
            class="ym-upload"
            v-model:file-list="fileList"
            :action="action"
            :headers="headers"
            :list-type="isList ? 'picture-card' : 'picture'"
            :show-file-list="isList"
            :name="name"
            :limit="limit"
            :multiple="isList"
            :on-exceed="handleExceed"
            :on-success="uploadSuccess"
            :on-remove="handleRemove"
            :on-preview="handlePictureCardPreview">
            <el-icon v-if="isList" :size="30"><Plus /></el-icon>
            <!-- 单文件非列表 -->
            <div v-else class="box" style="position: relative">
                <template v-if="model">
                    <div class="ym-upload-tip" @click.stop="handleSigleRemove">
                        <el-icon :size="18" color="red"><RemoveFilled /></el-icon>
                    </div>
                    <el-image :style="getImgStyle" :src="model as string" />
                </template>
                <el-icon v-else class="icon" :style="getImgStyle">
                    <Plus />
                </el-icon>
                <div class="body">
                    <slot />
                </div>
            </div>
        </el-upload>
        <el-dialog v-model="dialogVisible">
            <el-image :src="dialogImageUrl" alt="预览" />
        </el-dialog>
    </div>
</template>

<script setup lang="ts">
    import { ref } from 'vue'
    import { Plus } from '@element-plus/icons-vue'
    import type { UploadProps, UploadUserFile } from 'element-plus'
    // import { ElMessage, ElMessageBox } from 'element-plus'
    const model = defineModel<string | string[]>()
    const props = defineProps({
        modelValue: {
            type: [String, Array],
            default: ''
        },
        //上传的文件字段名
        name: {
            type: String,
            default: 'file'
        },
        size: {
            type: Number,
            default: 90
        },
        width: {
            type: Number,
            default: 90
        },
        height: {
            type: Number,
            default: 90
        },
        //允许上传文件的最大数量(0不限制)
        limit: {
            type: Number,
            default: 0
        },
        action: {
            type: String,
            default: () => {
                const baseUrl = import.meta.env.VITE_API_HOST
                if (import.meta.env.VITE_API_IMAGE_UPLOAD) {
                    return baseUrl + import.meta.env.VITE_API_IMAGE_UPLOAD
                }
                return baseUrl + '/upload/image'
            }
        },
        isList: {
            type: Boolean,
            default: false
        },
        headers: {
            type: Object,
            default: () => {
                return {
                    Authorization: 'Bearer ' + localStorage.getItem('token')
                }
            }
        }
    })
    const fileList = ref<UploadUserFile[]>([])
    const dialogImageUrl = ref('')
    const dialogVisible = ref(false)

    onMounted(() => {
        if (Array.isArray(model.value)) {
            fileList.value = model.value.map((item: any) => {
                return {
                    name: '',
                    url: item
                }
            })
        }
    })
    /**
     * 预览图片宽高样式
     * @type {ComputedRef<{width: string, height: string}>}
     */
    const getImgStyle = computed(() => {
        return {
            height: props.height + 'px',
            width: props.width + 'px'
        }
    })
    /**
     * 上传成功
     */
    const uploadSuccess: UploadProps['onSuccess'] = (response, uploadFile) => {
        if (response.code !== 0) {
            ElMessage.error(response.msg)
            return
        }
        if (props.isList && Array.isArray(model.value)) {
            model.value.push(response.data.fullPath)
        } else {
            model.value = response.data.fullPath
        }
    }
    /**
     * 图片预览
     * @param uploadFile
     */
    const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile: any) => {
        dialogImageUrl.value = uploadFile.url
        dialogVisible.value = true
    }
    /**
     * 移除图片事件（多张图片）
     * @param uploadFile
     */
    const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => {
        model.value = uploadFiles.map((item: any) => {
            return item.response ? item.response.data.fullPath : item.url
        })
    }
    /**
     * 移除图片事件（单张图片）
     * @param uploadFile
     */
    const handleSigleRemove = () => {
        ElMessageBox.confirm('确认删除吗？', '提示', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning'
        }).then(() => {
            model.value = ''
        })
    }
    /**
     * 超出上传数量
     * @param files
     * @param uploadFiles
     */
    const handleExceed: UploadProps['onExceed'] = (files, uploadFiles) => {
        ElMessage.warning('最多只能上传' + props.limit + '张图片')
    }
</script>

<style lang="scss" scoped>
    .ym-upload {
        display: flex;
        border: 1px dashed var(--el-border-color, #ccc);
        border-radius: 6px;
        cursor: pointer;
        position: relative;
        overflow: hidden;
        transition: var(--el-transition-duration-fast);
        &:hover {
            border-color: var(--el-color-primary);
        }
        .box {
            position: relative;
            display: flex;
            .body {
                position: absolute;
                left: 0;
                right: 0;
                bottom: 0;
                text-align: center;
                background-color: rgba(0, 0, 0, 0.4);
                color: #fff;
                line-height: 24px;
                font-size: 12px;
            }
            .ym-upload-tip {
                z-index: 999;
                position: absolute;
                top: 0;
                right: 2px;
                opacity: 0;
                transition: all 0.6s;
            }
            &:hover {
                .ym-upload-tip {
                    opacity: 1;
                }
            }
        }
        .icon {
            font-size: 28px;
            color: #8c939d;
            text-align: center;
        }
    }
</style>
